package edu.ynu.se.xiecheng.achitectureclass.digitalagriculture.service;

import edu.ynu.se.xiecheng.achitectureclass.digitalagriculture.dao.DeviceDAO;
import edu.ynu.se.xiecheng.achitectureclass.digitalagriculture.entity.DeviceEntity;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.List;

/**
 * 设备服务类
 * 设计原则体现：
 * 1. 单一职责原则(SRP) - 该类专注于设备相关的业务逻辑
 * 2. 依赖注入原则(DI) - 通过构造函数注入所需的DAO
 */
@Service
public class DeviceService {

    private final DeviceDAO deviceDAO;

    public DeviceService(DeviceDAO deviceDAO) {
        this.deviceDAO = deviceDAO; // 依赖注入
    }

    /**
     * 根据设备序列号获取设备
     * 设计原则体现：
     * 1. 高内聚 - 方法功能单一，专注于获取设备
     * 2. 关注点分离 - 数据访问逻辑与业务逻辑分离
     */
    public DeviceEntity getDeviceBySn(String sn) {
        List<DeviceEntity> all = deviceDAO.findAll(new Specification<DeviceEntity>() {
            @Override
            public Predicate toPredicate(Root<DeviceEntity> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                List<Predicate> list = new ArrayList<>();
                list.add(criteriaBuilder.equal(root.get("sn"), sn));
                return criteriaBuilder.and(list.toArray(new Predicate[0]));
            }
        });

        if (!all.isEmpty()) {
            return all.get(0);
        }

        return null; // 处理未找到设备的情况
    }

    /**
     * 根据ID获取设备
     * 设计原则体现：
     * 1. 单一职责原则 - 方法只负责根据ID获取设备
     * 2. 依赖倒置原则 - 通过DAO接口获取数据
     */
    public DeviceEntity getById(Long id) {
        return deviceDAO.findById(id).orElse(null);
    }

    /**
     * 根据ID和类型获取设备列表
     * 设计原则体现：
     * 1. 开放封闭原则(OCP) - 方法支持不同的查询条件
     * 2. 关注点分离 - 数据访问逻辑与业务逻辑分离
     */
    public List<DeviceEntity> getDeviceByBoxId(Long boxId, String type) {
        List<DeviceEntity> all = deviceDAO.findAll(new Specification<DeviceEntity>() {
            @Override
            public Predicate toPredicate(Root<DeviceEntity> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                List<Predicate> list = new ArrayList<>();
                list.add(criteriaBuilder.equal(root.get("greenhouseId"), boxId));
                list.add(criteriaBuilder.equal(root.get("type"), type));
                return criteriaBuilder.and(list.toArray(new Predicate[0]));
            }
        });

        return all; // 返回符合条件的设备列表
    }

    /**
     * 根据ID删除设备
     * 设计原则体现：
     * 1. 事务管理 - 确保删除操作的原子性
     * 2. 单一职责原则 - 方法只负责删除设备
     */
    public void removeById(Long id) {
        deviceDAO.deleteById(id);
    }

    /**
     * 保存设备
     * 设计原则体现：
     * 1. 事务管理 - 确保保存操作的原子性
     * 2. 单一职责原则 - 方法只负责保存设备
     */
    public void save(DeviceEntity deviceEntity) {
        deviceDAO.save(deviceEntity);
    }

    /**
     * 分页查询设备
     * 设计原则体现：
     * 1. 开放封闭原则(OCP) - 方法支持不同的分页需求
     * 2. 迪米特法则 - 只与直接依赖的DAO交互
     */
    public Page<DeviceEntity> page(Integer current, Integer size) {
        Page<DeviceEntity> page = deviceDAO.findAll(PageRequest.of(current, size));
        return page; // 返回分页结果
    }
}
